home *** CD-ROM | disk | FTP | other *** search
/ MPEG Toolkit / MPEG Toolkit.iso / os2 / mpegenc / src / iframe.c < prev    next >
C/C++ Source or Header  |  1997-01-01  |  19KB  |  735 lines

  1. /*===========================================================================*
  2.  * iframe.c                                     *
  3.  *                                         *
  4.  *    Procedures concerned with the I-frame encoding                 *
  5.  *                                         *
  6.  * EXPORTED PROCEDURES:                                 *
  7.  *    GenIFrame                                 *
  8.  *    SetSlicesPerFrame                             *
  9.  *    SetBlocksPerSlice                             *
  10.  *    SetIQScale                                 *
  11.  *    ResetIFrameStats                             *
  12.  *    ShowIFrameSummary                             *
  13.  *    EstimateSecondsPerIFrame                         *
  14.  *    EncodeYDC                                 *
  15.  *    EncodeCDC                                 *
  16.  *                                         *
  17.  *===========================================================================*/
  18.  
  19. /*
  20.  * Copyright (c) 1993 The Regents of the University of California.
  21.  * All rights reserved.
  22.  *
  23.  * Permission to use, copy, modify, and distribute this software and its
  24.  * documentation for any purpose, without fee, and without written agreement is
  25.  * hereby granted, provided that the above copyright notice and the following
  26.  * two paragraphs appear in all copies of this software.
  27.  *
  28.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  29.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  30.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  31.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.  *
  33.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  34.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  35.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  36.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  37.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  38.  */
  39.  
  40. /*
  41.  *  $Header: /n/picasso/users/keving/encode/src/RCS/iframe.c,v 1.6 1993/07/22 22:23:43 keving Exp keving $
  42.  *  $Log: iframe.c,v $
  43.  * Revision 1.6  1993/07/22  22:23:43  keving
  44.  * nothing
  45.  *
  46.  * Revision 1.5  1993/06/30  20:06:09  keving
  47.  * nothing
  48.  *
  49.  * Revision 1.4  1993/06/03  21:08:08  keving
  50.  * nothing
  51.  *
  52.  * Revision 1.3  1993/03/04  22:24:06  keving
  53.  * nothing
  54.  *
  55.  * Revision 1.2  1993/02/19  18:10:02  keving
  56.  * nothing
  57.  *
  58.  * Revision 1.1  1993/02/18  22:56:39  keving
  59.  * nothing
  60.  *
  61.  *
  62.  */
  63.  
  64.  
  65. /*==============*
  66.  * HEADER FILES *
  67.  *==============*/
  68.  
  69. /* @@@ Fake up 'times' interface under OS/2, Andy Key */
  70. #ifdef OS2
  71. #include "os2port.h"
  72. #else
  73. #include <sys/times.h>
  74. #endif
  75. #include "all.h"
  76. #include "mtypes.h"
  77. #include "frames.h"
  78. #ifdef OS2
  79. /* @@@ FAT 8.3 convention */
  80. #include "prototyp.h"
  81. #else
  82. #include "prototypes.h"
  83. #endif
  84. #include "mpeg.h"
  85. #include "param.h"
  86. #include "mheaders.h"
  87. #include "fsize.h"
  88. #include "parallel.h"
  89. #include "postdct.h"
  90.  
  91.  
  92. /*==================*
  93.  * STATIC VARIABLES *
  94.  *==================*/
  95.  
  96. static int numBlocks = 0;
  97. static int numBits;
  98. static int numFrames = 0;
  99. static int numFrameBits = 0;
  100. static int32 totalTime = 0;
  101. static float    totalSNR = 0.0;
  102. static float    totalPSNR = 0.0;
  103.  
  104.  
  105. /*==================*
  106.  * GLOBAL VARIABLES *
  107.  *==================*/
  108.  
  109. int    qscaleI;
  110. int    slicesPerFrame;
  111. int    blocksPerSlice;
  112. int    fCode;
  113. boolean    printSNR = FALSE;
  114. boolean    decodeRefFrames = FALSE;
  115.  
  116.  
  117. /*=====================*
  118.  * EXPORTED PROCEDURES *
  119.  *=====================*/
  120.  
  121.  
  122. /*===========================================================================*
  123.  *
  124.  * SetFCode
  125.  *
  126.  *    set the forward_f_code and backward_f_code according to the search
  127.  *    range.  Must be called AFTER pixelFullSearch and searchRange have
  128.  *    been initialized.  Irrelevant for I-frames, but computation is
  129.  *    negligible (done only once, as well)
  130.  *
  131.  * RETURNS:    nothing
  132.  *
  133.  * SIDE EFFECTS:    fCode
  134.  *
  135.  *===========================================================================*/
  136. void
  137. SetFCode()
  138. {
  139.     int        range;
  140.  
  141.     if ( pixelFullSearch ) {
  142.     range = searchRange;
  143.     } else {
  144.     range = searchRange*2;
  145.     }
  146.  
  147.     if ( range < 256 ) {
  148.     if ( range < 64 ) {
  149.         if ( range < 32 ) {
  150.         fCode = 1;
  151.         } else {
  152.         fCode = 2;
  153.         }
  154.     } else {
  155.         if ( range < 128 ) {
  156.         fCode = 3;
  157.         } else {
  158.         fCode = 4;
  159.         }
  160.     }
  161.     } else {
  162.     if ( range < 1024 ) {
  163.         if ( range < 512 ) {
  164.         fCode = 5;
  165.         } else {
  166.         fCode = 6;
  167.         }
  168.     } else {
  169.         if ( range < 2048 ) {
  170.         fCode = 7;
  171.         } else {
  172.         fprintf(stdout, "ERROR:  INVALID SEARCH RANGE!!!\n");
  173.         exit(1);
  174.         }
  175.     }
  176.     }
  177. }
  178.  
  179.  
  180. /*===========================================================================*
  181.  *
  182.  * SetSlicesPerFrame
  183.  *
  184.  *    set the number of slices per frame
  185.  *
  186.  * RETURNS:    nothing
  187.  *
  188.  * SIDE EFFECTS:    slicesPerFrame
  189.  *
  190.  *===========================================================================*/
  191. void
  192. SetSlicesPerFrame(number)
  193.     int number;
  194. {
  195.     slicesPerFrame = number;
  196. }
  197.  
  198.  
  199. /*===========================================================================*
  200.  *
  201.  * SetBlocksPerSlice
  202.  *
  203.  *    set the number of blocks per slice, based on slicesPerFrame
  204.  *
  205.  * RETURNS:    nothing
  206.  *
  207.  * SIDE EFFECTS:    blocksPerSlice
  208.  *
  209.  *===========================================================================*/
  210. void
  211. SetBlocksPerSlice()
  212. {
  213.     int        totalBlocks;
  214.  
  215.     totalBlocks = (Fsize_y/16)*(Fsize_x/16);
  216.  
  217.     if ( slicesPerFrame > totalBlocks ) {
  218.     blocksPerSlice = 1;
  219.     } else {
  220.     blocksPerSlice = totalBlocks/slicesPerFrame;
  221.     }
  222. }
  223.  
  224.  
  225. /*===========================================================================*
  226.  *
  227.  * SetIQScale
  228.  *
  229.  *    set the I-frame Q-scale
  230.  *
  231.  * RETURNS:    nothing
  232.  *
  233.  * SIDE EFFECTS:    qscaleI
  234.  *
  235.  *===========================================================================*/
  236. void
  237. SetIQScale(qI)
  238. int qI;
  239. {
  240.     qscaleI = qI;
  241. }
  242.  
  243.  
  244. /*===========================================================================*
  245.  *
  246.  * GenIFrame
  247.  *
  248.  *    generate an I-frame; appends result to bb
  249.  *
  250.  * RETURNS:    I-frame appended to bb
  251.  *
  252.  * SIDE EFFECTS:    none
  253.  *
  254.  *===========================================================================*/
  255. void
  256. GenIFrame(bb, current)
  257.     BitBucket *bb;
  258.     MpegFrame *current;
  259. {
  260.     register int x, y;
  261.     register int index;
  262.     FlatBlock    fb[6];
  263.     Block    dec[6];
  264.     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
  265.     int totalBits;
  266.     int    totalFrameBits;
  267.     struct tms timeBuffer;
  268.     int32    startTime, endTime;
  269.     int        frameBlocks;
  270.     float   snr[3], psnr[3];
  271.  
  272.     /* set-up for statistics */
  273.     numFrames++;
  274.     totalFrameBits = bb->cumulativeBits;
  275.     times(&timeBuffer);
  276.     startTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  277.  
  278.     Frame_AllocBlocks(current);
  279.     BlockifyFrame(current);
  280.  
  281.     DBG_PRINT(("Generating iframe\n"));
  282.  
  283.     Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCode);
  284.     Mhead_GenSliceHeader(bb, 1, qscaleI, NULL, 0);
  285.  
  286.     if ( referenceFrame == DECODED_FRAME ) {
  287.     Frame_AllocDecoded(current, TRUE);
  288.     } else if ( printSNR ) {
  289.     Frame_AllocDecoded(current, FALSE);
  290.     }
  291.  
  292.     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  293.     totalBits = bb->cumulativeBits;
  294.     frameBlocks = 0;
  295.     for (y = 0; y < Fsize_y / 8; y += 2) {
  296.     for (x = 0; x < Fsize_x / 8; x += 2) {
  297.         /* DCT this macroblock */
  298.         mp_fwd_dct_block(current->y_blocks[y][x]);
  299.         mp_fwd_dct_block(current->y_blocks[y][x+1]);
  300.         mp_fwd_dct_block(current->y_blocks[y+1][x]);
  301.         mp_fwd_dct_block(current->y_blocks[y+1][x+1]);
  302.         mp_fwd_dct_block(current->cr_blocks[y>>1][x>>1]);
  303.         mp_fwd_dct_block(current->cb_blocks[y>>1][x>>1]);
  304.  
  305.         if ( (frameBlocks % blocksPerSlice == 0) && (frameBlocks != 0) ) {
  306.         /* create a new slice */
  307.         Mhead_GenSliceEnder(bb);
  308.         Mhead_GenSliceHeader(bb, 1+(y/2), qscaleI, NULL, 0);
  309.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  310.  
  311.         GEN_I_BLOCK(I_FRAME, current, bb, 1+(x/2), qscaleI);
  312.         } else {
  313.         GEN_I_BLOCK(I_FRAME, current, bb, 1, qscaleI);
  314.         }
  315.  
  316.         if ( decodeRefFrames ) {
  317.         /* need to decode block we just encoded */
  318.         Mpost_UnQuantZigBlock(fb[0], dec[0], qscaleI, TRUE);
  319.         Mpost_UnQuantZigBlock(fb[1], dec[1], qscaleI, TRUE);
  320.         Mpost_UnQuantZigBlock(fb[2], dec[2], qscaleI, TRUE);
  321.         Mpost_UnQuantZigBlock(fb[3], dec[3], qscaleI, TRUE);
  322.         Mpost_UnQuantZigBlock(fb[4], dec[4], qscaleI, TRUE);
  323.         Mpost_UnQuantZigBlock(fb[5], dec[5], qscaleI, TRUE);
  324.  
  325.         /* now, reverse the DCT transform */
  326.         for ( index = 0; index < 6; index++ ) {
  327.             j_rev_dct((int16 *)dec[index]);        
  328.         }
  329.  
  330.         /* now, unblockify */
  331.         BlockToData(current->decoded_y, dec[0], y, x);
  332.         BlockToData(current->decoded_y, dec[1], y, x+1);
  333.         BlockToData(current->decoded_y, dec[2], y+1, x);
  334.         BlockToData(current->decoded_y, dec[3], y+1, x+1);
  335.         BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
  336.         BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
  337.         }
  338.  
  339.         numBlocks++;
  340.         frameBlocks++;
  341.     }
  342.     }
  343.  
  344.     if ( printSNR ) {
  345.         ComputeSNR(current->orig_y, current->decoded_y, Fsize_y, Fsize_x,
  346.            &snr[0], &psnr[0]);
  347.         ComputeSNR(current->orig_cb, current->decoded_cb, Fsize_y/2, Fsize_x/2,
  348.            &snr[1], &psnr[1]);
  349.         ComputeSNR(current->orig_cr, current->decoded_cr, Fsize_y/2, Fsize_x/2,
  350.            &snr[2], &psnr[2]);
  351.  
  352.     totalSNR += snr[0];
  353.     totalPSNR += psnr[0];
  354.     }
  355.  
  356.     if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
  357.     if ( remoteIO ) {
  358.         SendDecodedFrame(current);
  359.     } else {
  360.         WriteDecodedFrame(current);
  361.     }
  362.  
  363.     /* now, tell decode server it is ready */
  364.     NotifyDecodeServerReady(current->id);
  365.     }
  366.  
  367.     numBits += (bb->cumulativeBits-totalBits);
  368.  
  369.     DBG_PRINT(("End of frame\n"));
  370.  
  371.     Mhead_GenSliceEnder(bb);
  372.  
  373.     times(&timeBuffer);
  374.     endTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  375.     totalTime += (endTime-startTime);
  376.  
  377.     numFrameBits += (bb->cumulativeBits-totalFrameBits);
  378.  
  379.     if ( (! childProcess) && frameSummary ) {
  380.     fprintf(stdout, "FRAME %d (I):  %ld seconds\n", 
  381.         current->id, (long)((endTime-startTime)/60));
  382.     if ( printSNR ) {
  383.         fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
  384.             current->id, snr[0], snr[1], snr[2],
  385.             psnr[0], psnr[1], psnr[2]);
  386.     }
  387.     }
  388. }
  389.  
  390.  
  391. /*===========================================================================*
  392.  *
  393.  * ResetIFrameStats
  394.  *
  395.  *    reset the I-frame statistics
  396.  *
  397.  * RETURNS:    nothing
  398.  *
  399.  * SIDE EFFECTS:    none
  400.  *
  401.  *===========================================================================*/
  402. void
  403. ResetIFrameStats()
  404. {
  405.     numBlocks = 0;
  406.     numBits = 0;
  407.     numFrames = 0;
  408.     numFrameBits = 0;
  409.     totalTime = 0;
  410. }
  411.  
  412.  
  413. /*===========================================================================*
  414.  *
  415.  * ShowIFrameSummary
  416.  *
  417.  *    prints out statistics on all I-frames
  418.  *
  419.  * RETURNS:    nothing
  420.  *
  421.  * SIDE EFFECTS:    none
  422.  *
  423.  *===========================================================================*/
  424. void
  425. ShowIFrameSummary(inputFrameBits, totalBits, fpointer)
  426.     int inputFrameBits;
  427.     int32 totalBits;
  428.     FILE *fpointer;
  429. {
  430.     if ( numFrames == 0 ) {
  431.     return;
  432.     }
  433.  
  434.     fprintf(fpointer, "-------------------------\n");
  435.     fprintf(fpointer, "*****I FRAME SUMMARY*****\n");
  436.     fprintf(fpointer, "-------------------------\n");
  437.  
  438.     fprintf(fpointer, "  Blocks:    %5d     (%6d bits)     (%5d bpb)\n",
  439.         numBlocks, numBits, numBits/numBlocks);
  440.     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
  441.         numFrames, numFrameBits, numFrameBits/numFrames,
  442.         100.0*(float)numFrameBits/(float)totalBits);
  443.     fprintf(fpointer, "  Compression:  %3d:1\n",
  444.         numFrames*inputFrameBits/numFrameBits);
  445.     if ( printSNR )
  446.     fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
  447.         totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
  448.     fprintf(fpointer, "  Seconds:  %9ld     (%9ld spf)     (%9ld bps)\n",
  449.         (long)(totalTime/60), (long)(totalTime/(60*numFrames)),
  450.         (long)(60.0*(float)numFrames*(float)inputFrameBits/(float)totalTime));
  451. }
  452.  
  453.  
  454. /*===========================================================================*
  455.  *
  456.  * EstimateSecondsPerIFrame
  457.  *
  458.  *    estimates the number of seconds required per I-frame
  459.  *
  460.  * RETURNS:    seconds (floating point value)
  461.  *
  462.  * SIDE EFFECTS:    none
  463.  *
  464.  *===========================================================================*/
  465. float
  466. EstimateSecondsPerIFrame()
  467. {
  468.     return (float)totalTime/(60.0*(float)numFrames);
  469. }
  470.  
  471.  
  472. /*===========================================================================*
  473.  *
  474.  * EncodeYDC
  475.  *
  476.  *    Encode the DC portion of a DCT of a luminance block
  477.  *
  478.  * RETURNS:    result appended to bb
  479.  *
  480.  * SIDE EFFECTS:    updates pred_term
  481.  *
  482.  *===========================================================================*/
  483. void
  484. EncodeYDC(dc_term, pred_term, bb)
  485.     int32 dc_term;
  486.     int32 *pred_term;
  487.     BitBucket *bb;
  488. {
  489.     int ydiff, ydiff_abs;
  490.  
  491.     ydiff = (dc_term - (*pred_term));
  492.     if (ydiff > 255) {
  493.     ydiff = 255;
  494.     } else if (ydiff < -255) {
  495.     ydiff = -255;
  496.     }
  497.  
  498.     ydiff_abs = ABS(ydiff);
  499.  
  500.     if (ydiff_abs == 0) {
  501.     Bitio_Write(bb, 0x4, 3);
  502.     } else if (ydiff_abs & 0x80) {
  503.     Bitio_Write(bb, 0x7e, 7);
  504.     if (ydiff > 0) {
  505.         Bitio_Write(bb, ydiff_abs, 8);
  506.     } else
  507.         Bitio_Write(bb, ~ydiff_abs, 8);
  508.     } else if (ydiff_abs & 0x40) {
  509.     Bitio_Write(bb, 0x3e, 6);
  510.     if (ydiff > 0) {
  511.         Bitio_Write(bb, ydiff_abs, 7);
  512.     } else {
  513.         Bitio_Write(bb, ~ydiff_abs, 7);
  514.     }
  515.     } else if (ydiff_abs & 0x20) {
  516.     Bitio_Write(bb, 0x1e, 5);
  517.     if (ydiff > 0) {
  518.         Bitio_Write(bb, ydiff_abs, 6);
  519.     } else {
  520.         Bitio_Write(bb, ~ydiff_abs, 6);
  521.     }
  522.     } else if (ydiff_abs & 0x10) {
  523.     Bitio_Write(bb, 0xe, 4);
  524.     if (ydiff > 0) {
  525.         Bitio_Write(bb, ydiff_abs, 5);
  526.     } else {
  527.         Bitio_Write(bb, ~ydiff_abs, 5);
  528.     }
  529.     } else if (ydiff_abs & 0x08) {
  530.     Bitio_Write(bb, 0x6, 3);
  531.     if (ydiff > 0) {
  532.         Bitio_Write(bb, ydiff_abs, 4);
  533.     } else {
  534.         Bitio_Write(bb, ~ydiff_abs, 4);
  535.     }
  536.     } else if (ydiff_abs & 0x04) {
  537.     Bitio_Write(bb, 0x5, 3);
  538.     if (ydiff > 0) {
  539.         Bitio_Write(bb, ydiff_abs, 3);
  540.     } else {
  541.         Bitio_Write(bb, ~ydiff_abs, 3);
  542.     }
  543.     } else if (ydiff_abs & 0x02) {
  544.     Bitio_Write(bb, 0x1, 2);
  545.     if (ydiff > 0) {
  546.         Bitio_Write(bb, ydiff_abs, 2);
  547.     } else {
  548.         Bitio_Write(bb, ~ydiff_abs, 2);
  549.     }
  550.     } else if (ydiff_abs & 0x01) {
  551.     Bitio_Write(bb, 0x0, 2);
  552.     if (ydiff > 0) {
  553.         Bitio_Write(bb, ydiff_abs, 1);
  554.     } else {
  555.         Bitio_Write(bb, ~ydiff_abs, 1);
  556.     }
  557.     } else {
  558.     fprintf(stderr, "ERROR in EncodeYDC\n");
  559.     exit(1);
  560.     }
  561.  
  562.     (*pred_term) += ydiff;
  563. }
  564.  
  565.  
  566. /*===========================================================================*
  567.  *
  568.  * EncodeCDC
  569.  *
  570.  *    Encode the DC portion of a DCT of a chrominance block
  571.  *
  572.  * RETURNS:    result appended to bb
  573.  *
  574.  * SIDE EFFECTS:    updates pred_term
  575.  *
  576.  *===========================================================================*/
  577. void
  578. EncodeCDC(dc_term, pred_term, bb)
  579.     int32 dc_term;
  580.     int32 *pred_term;
  581.     BitBucket *bb;
  582. {
  583.     int cdiff, cdiff_abs;
  584.  
  585.     cdiff = (dc_term - (*pred_term));
  586.     if (cdiff > 255) {
  587.     cdiff = 255;
  588.     } else if (cdiff < -255) {
  589.     cdiff = -255;
  590.     }
  591.  
  592.     cdiff_abs = ABS(cdiff);
  593.  
  594.     if (cdiff_abs == 0) {
  595.     Bitio_Write(bb, 0x0, 2);
  596.     } else if (cdiff_abs & 0x80) {
  597.     Bitio_Write(bb, 0xfe, 8);
  598.     if (cdiff > 0) {
  599.         Bitio_Write(bb, cdiff_abs, 8);
  600.     } else {
  601.         Bitio_Write(bb, ~cdiff_abs, 8);
  602.     }
  603.     } else if (cdiff_abs & 0x40) {
  604.     Bitio_Write(bb, 0x7e, 7);
  605.     if (cdiff > 0) {
  606.         Bitio_Write(bb, cdiff_abs, 7);
  607.     } else {
  608.         Bitio_Write(bb, ~cdiff_abs, 7);
  609.     }
  610.     } else if (cdiff_abs & 0x20) {
  611.     Bitio_Write(bb, 0x3e, 6);
  612.     if (cdiff > 0) {
  613.         Bitio_Write(bb, cdiff_abs, 6);
  614.     } else {
  615.         Bitio_Write(bb, ~cdiff_abs, 6);
  616.     }
  617.     } else if (cdiff_abs & 0x10) {
  618.     Bitio_Write(bb, 0x1e, 5);
  619.     if (cdiff > 0) {
  620.         Bitio_Write(bb, cdiff_abs, 5);
  621.     } else {
  622.         Bitio_Write(bb, ~cdiff_abs, 5);
  623.     }
  624.     } else if (cdiff_abs & 0x08) {
  625.     Bitio_Write(bb, 0xe, 4);
  626.     if (cdiff > 0) {
  627.         Bitio_Write(bb, cdiff_abs, 4);
  628.     } else {
  629.         Bitio_Write(bb, ~cdiff_abs, 4);
  630.     }
  631.     } else if (cdiff_abs & 0x04) {
  632.     Bitio_Write(bb, 0x6, 3);
  633.     if (cdiff > 0) {
  634.         Bitio_Write(bb, cdiff_abs, 3);
  635.     } else {
  636.         Bitio_Write(bb, ~cdiff_abs, 3);
  637.     }
  638.     } else if (cdiff_abs & 0x02) {
  639.     Bitio_Write(bb, 0x2, 2);
  640.     if (cdiff > 0) {
  641.         Bitio_Write(bb, cdiff_abs, 2);
  642.     } else {
  643.         Bitio_Write(bb, ~cdiff_abs, 2);
  644.     }
  645.     } else if (cdiff_abs & 0x01) {
  646.     Bitio_Write(bb, 0x1, 2);
  647.     if (cdiff > 0) {
  648.         Bitio_Write(bb, cdiff_abs, 1);
  649.     } else {
  650.         Bitio_Write(bb, ~cdiff_abs, 1);
  651.     }
  652.     } else {
  653.     fprintf(stderr, "ERROR in EncodeCDC\n");
  654.     exit(1);
  655.     }
  656.  
  657.     (*pred_term) += cdiff;
  658. }
  659.  
  660.  
  661. void
  662. ComputeSNR(origData, newData, ySize, xSize, snr, psnr)
  663.      register uint8 **origData;
  664.      register uint8 **newData;
  665.      int ySize;
  666.      int xSize;
  667.      float *snr;
  668.      float *psnr;
  669. {
  670.     register int32    tempInt;
  671.     register int y, x;
  672.     int32    varOrig = 0;
  673.     int32    varDiff = 0;
  674.  
  675.     /* compute Y-plane SNR */
  676.     for ( y = 0; y < ySize; y++ ) {
  677.     for ( x = 0; x < xSize; x++ ) {
  678.         tempInt = origData[y][x];
  679.         varOrig += (tempInt*tempInt);
  680.     }
  681.     }
  682.  
  683.     for ( y = 0; y < ySize; y++ ) {
  684.     for ( x = 0; x < xSize; x++ ) {
  685.         tempInt = (origData[y][x]-newData[y][x]);
  686.         varDiff += (tempInt*tempInt);
  687.     }
  688.     }
  689.  
  690.     *snr = 10.0*log10((double)varOrig/(double)varDiff);
  691.     *psnr = 20.0*log10(255.0/sqrt((double)varDiff/(double)(ySize*xSize)));
  692. }
  693.  
  694.  
  695. void
  696. WriteDecodedFrame(frame)
  697.     MpegFrame *frame;
  698. {
  699.     FILE    *fpointer;
  700.     char    fileName[256];
  701.     int    width, height;
  702.     register int y;
  703.  
  704.     /* need to save decoded frame to disk because it might be accessed
  705.        by another process */
  706.  
  707.     width = Fsize_x;
  708.     height = Fsize_y;
  709.  
  710.     sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id);
  711.     fprintf(stdout, "outputting to %s\n", fileName);
  712.     fflush(stdout);
  713.  
  714. /* @@@ Open binary mode for OS/2, Andy Key */
  715. #ifdef OS2
  716.     fpointer = fopen(fileName, "wb");
  717. #else
  718.     fpointer = fopen(fileName, "w");
  719. #endif
  720.  
  721.     for ( y = 0; y < height; y++ ) {
  722.         fwrite(frame->decoded_y[y], 1, width, fpointer);
  723.     }
  724.  
  725.     for (y = 0; y < height / 2; y++) {            /* U */
  726.         fwrite(frame->decoded_cb[y], 1, width / 2, fpointer);
  727.     }
  728.  
  729.     for (y = 0; y < height / 2; y++) {            /* V */
  730.         fwrite(frame->decoded_cr[y], 1, width / 2, fpointer);
  731.     }
  732.  
  733.     fclose(fpointer);
  734. }
  735.